
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using System.IO;
using System;
using System.Reflection;

namespace MeEditor
{ 
    public class UXResolutionUtility
    {
        public static string resolutionAssetPath = Configure.ResAssetsPath + "/UIResoution.json";

        static object gameViewSizesInstance;
        static MethodInfo getGroup;
        static int currentIndex = -1;
        static UXResolutionAsset asset = null;
        static string prefsKey = "ResolutionCurrentIndex";
        static float timeInterval = 0.4f;
        static float currentTime = 0;
        static EditorApplication.CallbackFunction cb;
        public enum GameViewSizeType
        {
            AspectRatio, FixedResolution
        }
        [InitializeOnLoadMethod]
     
        static void Init()
        {
            var sizesType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.GameViewSizes");
            var singleType = typeof(ScriptableSingleton<>).MakeGenericType(sizesType);
            var instanceProp = singleType.GetProperty("instance");
            getGroup = sizesType.GetMethod("GetGroup");
            gameViewSizesInstance = instanceProp.GetValue(null, null);
            currentIndex = EditorPrefs.GetInt(prefsKey, -1);
            asset = GetResolutionCfg();
            asset.AddDefault();
            EditorApplication.update += Update;
            cb = SetCurrentIphoneFringe;
        }
        static UXResolutionUtility()
        {
            var sizesType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.GameViewSizes");
            var singleType = typeof(ScriptableSingleton<>).MakeGenericType(sizesType);
            var instanceProp = singleType.GetProperty("instance");
            getGroup = sizesType.GetMethod("GetGroup");
            gameViewSizesInstance = instanceProp.GetValue(null, null);
            currentIndex = EditorPrefs.GetInt(prefsKey, -1);
            asset = GetResolutionCfg();
        }

        static void Update()
        {
            if (currentTime > timeInterval)
            {
                if (cb != null)
                {
                    cb();
                    cb = null;
                }
                currentTime = 0;
            }
            else
            {
                currentTime += Time.deltaTime;
            }
        }


        //static void Edit()
        //{
        //    UXResolutionEditor.OpenEditor();
        //}


        [MenuItem("MeEditor/预设分辨率/前一个分辨率 &LEFT")]
        public static void PreResolution()
        {
            if (asset != null && asset.resolutions != null && asset.resolutions.Count > 0)
            {
                if (currentIndex == -1)
                {
                    currentIndex = 0;
                }
                else
                {
                    if (currentIndex > 0)
                    {
                        currentIndex--;
                    }
                }
                SetResolution(currentIndex);
            }
            else
            {
                Debug.LogWarning("未配置对应的分辨率");
                // if (EditorUtility.DisplayDialog("错误", "未配置对应的分辨率，点击确定开始配置。", "确定", "以后再说"))
                // {
                // //    Edit();
                // }
            }

        }

        [MenuItem("MeEditor/预设分辨率/后一个分辨率 &RIGHT")]
        public static void NextResolution()
        {
            if (asset != null && asset.resolutions != null && asset.resolutions.Count > 0)
            {
                if (currentIndex == -1)
                {
                    currentIndex = asset.resolutions.Count - 1;
                }
                else
                {
                    if (currentIndex < asset.resolutions.Count - 1)
                    {
                        currentIndex++;
                    }
                }
                SetResolution(currentIndex);
            }
            else
            {
                Debug.LogWarning("未配置对应的分辨率");
                //if (EditorUtility.DisplayDialog("错误", "未配置对应的分辨率，点击确定开始配置。", "确定", "以后再说"))
                //{
                //    Edit();
                //}
            }

        }

        public static void SetResolution(int idx)
        {
            if(idx < 0 || idx >= asset.resolutions.Count)
            {
                return;
            }
            currentIndex = idx;
            if(currentIndex < 0 || currentIndex >= asset.resolutions.Count)
            {
                currentIndex = 0;
            }
            EditorPrefs.SetInt(prefsKey, currentIndex);
            var temp = asset.resolutions[currentIndex];
            Vector2Int newSize = GetPortraitSize(temp);
            //NGUIFringe.EditorSetFringeValue(temp.iphoneFringeTop, temp.iphoneFringeBottom);
            var index = GetAndCreateSize(GetCurrentGroupType(), newSize.x, newSize.y, temp.Name);
            SetSize(index);
        }

        public static Vector2Int GetPortraitSize(UXResolution cfg)
        {
            var size = GetCurrentWidthAndHeight();
            bool isPortrait = size.x < size.y;
            int newWidth = cfg.width;
            int newHeight = cfg.height;
            if (cfg.width < cfg.height && !isPortrait)
            {
                newWidth = cfg.height;
                newHeight = cfg.width;
            }
            return new Vector2Int(newWidth, newHeight);
        }

        public static int GetCurrentResolutionIndex(UXResolutionAsset asset)
        {
            var size = GetCurrentWidthAndHeight();
            bool isPortrait = size.x < size.y;
            int index = -1;
            for (int i = asset.resolutions.Count - 1; i >= 0; i--)
            {
                var item = asset.resolutions[i];
                if (((item.width == size.x && item.height == size.y) || (item.width == size.y && item.height == size.x)) && currentIndex == i)
                {
                    index = i;
                    break;
                }
            }
            return index;
        }

        public static UXResolutionAsset GetResolutionCfg()
        {
            UXResolutionAsset asset = null;
            
            if(File.Exists(resolutionAssetPath)){
                string content = System.IO.File.ReadAllText(resolutionAssetPath);
                asset = JsonUtility.FromJson<UXResolutionAsset>(content);
            }
            // var textAsset = AssetDatabase.LoadAssetAtPath<TextAsset>(resolutionAssetPath);
            // if (textAsset != null)
            // {
            //     asset = JsonUtility.FromJson<UXResolutionAsset>(textAsset.text);
            // }
            return asset;
        }

        public static void SetCurrentIphoneFringe()
        {
            if (asset != null && asset.resolutions != null && asset.resolutions.Count > 0)
            {
                currentIndex = GetCurrentResolutionIndex(asset);
                if (currentIndex == -1)
                    return;
                var temp = asset.resolutions[currentIndex];
                Vector2Int newSize = GetPortraitSize(temp);
                //NGUIFringe.EditorSetFringeValue(temp.iphoneFringeTop, temp.iphoneFringeBottom);
                var index = GetAndCreateSize(GetCurrentGroupType(), newSize.x, newSize.y, temp.Name);
                SetSize(index);
            }
        }

        //[MenuItem("WGame/UXTools/切换到竖屏 &UP")]
        //static void ChangeUp()
        //{
        //    UXResolution resolution = null;
        //    if (currentIndex != -1 && asset != null && asset.resolutions != null && asset.resolutions.Count > 0)
        //    {
        //        resolution = asset.resolutions[currentIndex];
        //    }
        //    Vector2Int fringeSize = Vector2Int.zero;
        //    if (resolution != null)
        //    {
        //        fringeSize = new Vector2Int(resolution.iphoneFringeTop, resolution.iphoneFringeBottom);
        //        NGUIFringe.EditorSetFringeValue(resolution.iphoneFringeTop, resolution.iphoneFringeBottom);
        //    }
        //    var size = GetCurrentWidthAndHeight();
        //    if (size.x > size.y)
        //    {
        //        size = new Vector3Int(size.y, size.x, size.z);
        //    }

        //    int index = GetAndCreateSize(GetCurrentGroupType(), size.x, size.y, fringeSize.x, fringeSize.y, size.z);
        //    SetSize(index);
        //}


        //[MenuItem("WGame/UXTools/切换到横屏 &DOWN")]
        //static void ChangeDown()
        //{
        //    UXResolution resolution = null;
        //    if (currentIndex != -1 && asset != null && asset.resolutions != null && asset.resolutions.Count > 0)
        //    {
        //        resolution = asset.resolutions[currentIndex];
        //        NGUIFringe.EditorSetFringeValue(resolution.iphoneFringeTop, resolution.iphoneFringeBottom);
        //    }
        //    Vector2Int fringeSize = Vector2Int.zero;
        //    if (resolution != null)
        //    {
        //        fringeSize = new Vector2Int(resolution.iphoneFringeTop, resolution.iphoneFringeBottom);
        //    }
        //    var size = GetCurrentWidthAndHeight();
        //    if (size.x < size.y)
        //    {
        //        size = new Vector3Int(size.y, size.x, size.z);
        //    }
        //    int index = GetAndCreateSize(GetCurrentGroupType(), size.x, size.y, fringeSize.x, fringeSize.y, size.z);
        //    SetSize(index);
        //}

        /// <summary>
        /// x = width , y = height , z = [0=AspectRatio][1=FixedResolution]
        /// </summary>
        /// <returns></returns>
        public static Vector3Int GetCurrentWidthAndHeight()
        {
            var gvWndType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.GameView");
            var selectedSizeIndexProp = gvWndType.GetProperty("selectedSizeIndex",
                    BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            var gvWnd = EditorWindow.GetWindow(gvWndType);
            var currentGameViewSize = gvWndType.GetProperty("currentGameViewSize", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(gvWnd, null);

            var sizeGroupType = GetCurrentGroupType();
            var group = GetGroup(sizeGroupType);
            var groupType = group.GetType();
            var getGameViewSize = groupType.GetMethod("GetGameViewSize");
            var gvsType = getGameViewSize.ReturnType;

            var widthProp = gvsType.GetProperty("width");
            var heightProp = gvsType.GetProperty("height");
            var sizeTypeProp = gvsType.GetProperty("sizeType");



            int sizeWidth = (int)widthProp.GetValue(currentGameViewSize, null);
            int sizeHeight = (int)heightProp.GetValue(currentGameViewSize, null);
            int sizeType = (int)sizeTypeProp.GetValue(currentGameViewSize, null);
            return new Vector3Int(sizeWidth, sizeHeight, sizeType);
        }

        public static void SetSize(int index)
        {
            var gvWndType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.GameView");
            var selectedSizeIndexProp = gvWndType.GetProperty("selectedSizeIndex",
                    BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
            var gvWnd = EditorWindow.GetWindow(gvWndType);
            selectedSizeIndexProp.SetValue(gvWnd, index, null);
            var SnapZoomMethod = gvWndType.GetMethod("SnapZoom", BindingFlags.Instance | BindingFlags.NonPublic);
            var minScaleProp = gvWndType.GetProperty("minScale", BindingFlags.Instance | BindingFlags.NonPublic);
            //float minSacle = (float)minScaleProp.GetValue(gvWnd, null);
            //SnapZoomMethod.Invoke(gvWnd, new object[1] {  0.1f });
            cb = () => {
                float minSacle = (float)minScaleProp.GetValue(gvWnd, null);
                SnapZoomMethod.Invoke(gvWnd, new object[1] { minSacle });
            };
        }
        public static void AddCustomSize(object group, int width, int height, string text)
        {
            var addCustomSize = getGroup.ReturnType.GetMethod("AddCustomSize");
            var gvsType = typeof(UnityEditor.Editor).Assembly.GetType("UnityEditor.GameViewSize");

            var ctors = gvsType.GetConstructors();
            ConstructorInfo ctor = null;
            foreach (var item in ctors)
            {
                var p = item.GetParameters();
                if (p != null && p.Length == 4 && p[0].ParameterType.IsEnum && p[1].ParameterType == p[2].ParameterType && p[2].ParameterType == typeof(int) && p[3].ParameterType == typeof(string))
                {
                    ctor = item;
                    break;
                }
            }
            //var ctor = gvsType.GetConstructor(new Type[] { typeof(GameViewSizeType), typeof(int), typeof(int), typeof(string) });
            if (ctor != null)
            {

                var newSize = ctor.Invoke(new object[] { (int)1/*Fixed*/, width, height, text });

                addCustomSize.Invoke(group, new object[] { newSize });
            }
            else
            {
                Debug.LogError("Unity 版本不一致，需要更改此处的代码");
            }
        }


        public static int FindSize(GameViewSizeGroupType sizeGroupType, string text)
        {
            // GameViewSizes group = gameViewSizesInstance.GetGroup(sizeGroupType);
            // string[] texts = group.GetDisplayTexts();
            // for loop...

            var group = GetGroup(sizeGroupType);
            var getDisplayTexts = group.GetType().GetMethod("GetDisplayTexts");
            var displayTexts = getDisplayTexts.Invoke(group, null) as string[];
            for (int i = 0; i < displayTexts.Length; i++)
            {
                string display = displayTexts[i];
                // the text we get is "Name (W:H)" if the size has a name, or just "W:H" e.g. 16:9
                // so if we're querying a custom size text we substring to only get the name
                // You could see the outputs by just logging
                // Debug.Log(display);
                int pren = display.IndexOf('(');
                if (pren != -1)
                    display = display.Substring(0, pren - 1); // -1 to remove the space that's before the prens. This is very implementation-depdenent
                if (display == text)
                    return i;
            }
            return -1;
        }

        public static int GetTotalCount()
        {
            var group = GetGroup(GetCurrentGroupType());
            var groupType = group.GetType();
            var getTotalCount = groupType.GetMethod("GetTotalCount");
            return (int)getTotalCount.Invoke(group, null);
        }

        public static void RemoveCustomSize(UXResolution resolutionCfg)
        {
            GameViewSizeGroupType sizeGroupType = GetCurrentGroupType();
            var group = GetGroup(sizeGroupType);
            var groupType = group.GetType();
            var methods = groupType.GetMethods();
            var removeMethod = groupType.GetMethod("RemoveCustomSize");
            var getBuiltinCount = groupType.GetMethod("GetBuiltinCount");
            var getCustomCount = groupType.GetMethod("GetCustomCount");
            var getGameViewSize = groupType.GetMethod("GetGameViewSize");
            var gvsType = getGameViewSize.ReturnType;
            var properties = gvsType.GetProperties();
            var widthProp = gvsType.GetProperty("width");
            var heightProp = gvsType.GetProperty("height");
            var sizeTypeProp = gvsType.GetProperty("sizeType");
            var labelTypeProp = gvsType.GetProperty("baseText");
            int sizesCount = (int)getBuiltinCount.Invoke(group, null) + (int)getCustomCount.Invoke(group, null);
            var indexValue = new object[1];

            for (int i = 0; i < sizesCount; i++)
            {
                indexValue[0] = i;
                var size = getGameViewSize.Invoke(group, indexValue);
                int sizeWidth = (int)widthProp.GetValue(size, null);
                int sizeHeight = (int)heightProp.GetValue(size, null);
                int sizeType = (int)sizeTypeProp.GetValue(size, null);
                string label = (string)labelTypeProp.GetValue(size, null);
                Vector2Int fringeSize = Vector2Int.zero;
                if (!string.IsNullOrEmpty(label))
                {
                    string[] labelParts = label.Split(',');
                    if (labelParts.Length > 1)
                    {
                        string[] fringeStr = labelParts[1].Split('x');
                        int parsedTop = 0;
                        int parsedBottom = 0;
                        int.TryParse(fringeStr[0], out parsedTop);
                        int.TryParse(fringeStr[1], out parsedBottom);
                        fringeSize = new Vector2Int(parsedTop, parsedBottom);
                    }
                }
                if (sizeWidth == resolutionCfg.width && sizeHeight == resolutionCfg.height)
                {
                    removeMethod.Invoke(group, new object[] { i });
                    return;
                }
            }
        }

        public static int GetAndCreateSize(GameViewSizeGroupType sizeGroupType, int width, int height, string name)
        {
            // goal:
            // GameViewSizes group = gameViewSizesInstance.GetGroup(sizeGroupType);
            // int sizesCount = group.GetBuiltinCount() + group.GetCustomCount();
            // iterate through the sizes via group.GetGameViewSize(int index)

            var group = GetGroup(sizeGroupType);
            var groupType = group.GetType();
            var methods = groupType.GetMethods();
            var removeMethod = groupType.GetMethod("RemoveCustomSize");
            var getBuiltinCount = groupType.GetMethod("GetBuiltinCount");
            var getCustomCount = groupType.GetMethod("GetCustomCount");
            int sizesCount = (int)getBuiltinCount.Invoke(group, null) + (int)getCustomCount.Invoke(group, null);
            var getGameViewSize = groupType.GetMethod("GetGameViewSize");
            var gvsType = getGameViewSize.ReturnType;
            var properties = gvsType.GetProperties();
            var widthProp = gvsType.GetProperty("width");
            var heightProp = gvsType.GetProperty("height");
            var sizeTypeProp = gvsType.GetProperty("sizeType");
            var labelTypeProp = gvsType.GetProperty("baseText");
            var indexValue = new object[1];
            for (int i = 0; i < sizesCount; i++)
            {
                indexValue[0] = i;
                var size = getGameViewSize.Invoke(group, indexValue);
                int sizeWidth = (int)widthProp.GetValue(size, null);
                int sizeHeight = (int)heightProp.GetValue(size, null);
                int sizeType = (int)sizeTypeProp.GetValue(size, null);
                string label = (string)labelTypeProp.GetValue(size, null);
                Vector2Int fringeSize = Vector2Int.zero;
                if (!string.IsNullOrEmpty(label))
                {
                    string[] labelParts = label.Split(',');
                    if (labelParts.Length > 1)
                    {
                        string[] fringeStr = labelParts[1].Split('x');
                        int parsedTop = 0;
                        int parsedBottom = 0;
                        int.TryParse(fringeStr[0], out parsedTop);
                        int.TryParse(fringeStr[1], out parsedBottom);
                        fringeSize = new Vector2Int(parsedTop, parsedBottom);
                    }
                }
                if (sizeWidth == width && sizeHeight == height && fringeSize.y == fringeSize.y)
                    return i;
            }

            AddCustomSize(group, width, height, string.Format("[{0}]{1}x{2}", name, width, height));

            return GetTotalCount() - 1;
        }

        static object GetGroup(GameViewSizeGroupType type)
        {
            return getGroup.Invoke(gameViewSizesInstance, new object[] { (int)type });
        }
        public static GameViewSizeGroupType GetCurrentGroupType()
        {
            var getCurrentGroupTypeProp = gameViewSizesInstance.GetType().GetProperty("currentGroupType");
            return (GameViewSizeGroupType)(int)getCurrentGroupTypeProp.GetValue(gameViewSizesInstance, null);
        }

    }

    public class UXResolutionAsset
    {
        public List<UXResolution> resolutions = new List<UXResolution>();

        public void AddDefault()
        {
            resolutions.Insert(0, new UXResolution() { width = 1080, height = 2340, Name = "设计分辨率" });
        }
    }
    [System.Serializable]
    public class UXResolution
    {
        public int width;
        public int height;
        public string Name;
    }
}